Welcome back.
The next thing we need to do in our story is to start a countdown for completing the tasks, and then
we will wait for either the players to complete all their tasks, or for the countdown to reach zero.
Once that happens, we want to flicker the lights inside the building and lose power to continue our
story.
So let's get started.
After we have told our task service to set up all of the tasks, that means we're going to have to start
a countdown.
So what I'm going to do is I'm going to create a for loop, and this is going to loop for a number of
seconds.
So we can go back up here and we can create a constant section real quick.
And we can create a variable to represent how long we want to give the players to complete their tasks.
So we can call this time for tasks.
And we can do something like 100 and 20s then we can go back down to our for loop, and we could start
the index at our time for tasks.
And we want to go down all the way to zero.
And we want to subtract by one each time.
And what we're going to do in here is we're going to use our update GUI event, and we want to fire
to all of the clients, and we want to give them the action in our GUI actions enum of updating the
countdown.
And then what we want to do is we want to give them a number that is equal to the index.
And then we're going to yield for one second every single time.
So we're going to start at 100 and 20s.
And this is going to continually count down.
Now we need to either wait for this countdown to end, or we need to wait for the game comms event to
fire back to us so the task service can let us know that all the players completed their tasks.
So what I'm going to do is I'm actually going to create two variables up here.
I'm going to call it timed out and another one called Completed Tasks.
And these are going to be two booleans.
This will let us know whether or not we timed out.
And this will let us know if all the players completed their tasks or not.
And then what we're going to do is every single time in this for loop, we're going to check if we timed
out or if we completed our tasks.
If we did, then we can send out a warning like the timer was set to zero.
And then we can use our update guy event and fire to all of the clients to set their timers to zero.
So update countdown and we can set the number.
Equal to zero, then what we would want to do is we would also want to listen for our event to happen,
or wait until our loop is done.
In order to do this, we could create a function that would get passed an event, and it will also get
passed a time.
And this function will sit there and either wait for the event to fire or for the timeout to occur.
So what I'm going to do is I'm going to go up and I'm going to make a new private function, and I'm
going to call this private function wait for event.
And what we're going to do is we're going to pass this function, an event which is an ARB script signal.
And we're also going to get passed a number to represent the timeout.
And what we're going to do in this function is we're going to get the current running thread that is
executing here in this function, and we can get it by referring to our coroutine library and executing
the running function, which returns the current running coroutine, or basically the thread that is
executing in our function.
Then what we're also going to do is I'm going to make a connection to our event, because we're going
to be connecting a function to this event.
So we can call this event connection.
And for the time being we're going to set this to nil.
Then we can refer to our event connection and make it equal to this event.
And we're going to connect a lambda function to this event.
And then we're also going to use our task dot delay function.
And we're going to pass the time out here.
And we're also going to be executing a lambda function in here.
So we're going to have both of these listening simultaneously.
This function right here is going to be counting down.
And this one is going to be sitting here waiting for this event to fire.
So either this timeout will happen first or this event will get fired first.
Either way we're going to yield in this function until either the event fires or the timeout is reached.
Because what we're going to do is we're going to return at the end of our script, but we're going to
return using the coroutine dot yield function.
And this is going to pause or suspend the current thread inside of our wait for event function.
And that means we aren't able to resume until we're actually told to resume using the coroutine dot
resume function.
So when we call this function, it's going to sit there and yield until we either have this event fire
or this timeout is reached.
So for example, let's say the event fires what we could do.
Is we could use the coroutine dot resume function.
We can pass our current thread that is going to be paused to resume it, and when we resume it, that
means it's going to go back to this yield function and it's going to return whatever gets passed to
the yield function.
And whatever gets passed to this yield function, we can pass right here.
So if the event gets fired, that means we didn't time out.
So we can pass a boolean of false.
And we can also pass whatever information gets passed from this event.
So we could create three dots here to represent a variadic amount of arguments.
And then we can pass those arguments along with the coroutine dot resume function.
We can also do the exact same thing here on our task dot delay function.
We'll just copy this and we're going to resume the current thread.
But instead we're going to return true to signify that we did time out.
Right.
This function executed before this function.
Now let's say this function runs.
And then a second later this function runs.
How do we stop this function from also calling the coroutine dot resume function?
Well, what we could do for example inside of this lambda function, if the event gets fired, we can
get our event connection and we can disconnect it.
And then we can set the event connection equal to nil.
And this will allow us to know whether or not either of these lambda functions already disconnected,
and set this variable to nil.
So we can have an if statement in here to check if the event connection is equal to nil.
If it is, then we're just going to return out of the function because the other function already resumed
our current thread.
And we can basically just copy this and do the exact same check in here.
And we'll copy this and do the exact same thing in here.
So either this function here will resume our thread and return false.
Or this function right here will resume our thread and return true.
So now what we could do is we could refer to timed out and completed tasks and make it equal to whatever
gets returned from our wait for event function.
And the event we want to listen to is our game comms event or our game comms Rebindable.
So game comms bindable.
And we're going to wait for this to get fired.
And then we're also going to pass our time for tasks here.
So this function is either going to wait for this Bindable event to get fired, or it's going to wait
for our timeout to occur.
And this boolean will let us know whether or not we timed out.
And then we also pass from this event the action.
So if you remember, we go back to our task service when we completed all of our tasks.
Um, let me figure this out here, okay.
Yeah.
Right here.
When we complete our tasks, we fire, the game comes Bindable event, and we pass this action, which
is a string.
And since a string when put inside of a condition will be truthy, that means if we check what this
variable is, if it's a string, that means it's going to be truthy.
But if this event never got fired, then that means this is going to be nil or Falsy.
Now we're only going to be able to use this function if we actually spawn this for loop in another thread,
because currently the thread of execution will be stuck in this for loop, and it won't be able to go
to our wait for event function.
So we need to use task dot spawn.
And spawn a new function here, and then we can just take our for loop and put it inside of there.
And now we spawn our countdown.
And then immediately afterwards, we're waiting for our game Combinable event to get fired.
And we're also waiting for the timeout.
So either we'll time out or this event's going to get fired.
And when that happens, this will be set to either true or false, or this will be set to true or false.
So if we timed out this will be true.
And this will be false.
Or if we didn't time out this will be false and this will be truthy.
Which is why we're checking both conditions and our for loop.
Either way, after we have timed out or completed all of our tasks, we're going to use the game Combinable
and we're going to fire and give the action game comms enum server dot task service, and we're going
to tell it to disable all of the tasks.
And then what we could do is we could check whether or not we completed the tasks.
So if we completed tasks then we're going to go into our sections game sections, dot objectives, dot
tasks and set the fulfilled boolean to true.
And then we're going to use our update guy event and fire to all of the clients that we have fulfilled
an objective.
So Guy actions enum dot objective fulfilled.
And that objective is going to be the tasks objective.
So the fulfilled objective name is equal to tasks.
Otherwise, if we didn't complete our tasks, then we're just going to do the exact same thing here,
but instead we're going to tell them that they failed an objective so we can say objective failed.
And then the failed objective name is also going to be tasks.
So what we can do now is we can actually go ahead and test out whether or not our countdown is working.
So let's go in here and play test this.
All right.
Hopefully we get our timer showing up here.
And we did get all the tasks set up.
And unfortunately, it looks like we do not have a timer going on on these screens.
So we're going to have to figure out why real quick.
Oh, and the reason being is because we actually never filled out our update countdown function.
That's actually the next thing we need to do.
So this will be pretty easy.
Remember we get passed a number in this args table.
So we'll get the num equal to args dot number.
And then if this num is not equal to zero.
And if the countdown label we have dot text transparency is equal to one.
Then what we need to do is we need to fade our text onto the screen so we could use the fade element
function, pass our count down label.
We can do something like 0.25 seconds.
And we want to make it completely opaque because by default, our count down label is not going to be,
uh, clearly visible.
It's going to be transparent.
We also need to make sure that our countdown label is visible.
So countdown label dot visibility is equal to true.
And then what we could do is we could set the countdown label dot text equal to this number.
And then inside of the sound service inside of our guy folder, there is a tick sound, and we're going
to go ahead and play our tick sound.
And then afterwards, the last thing we need to check is if our number is zero.
So if the number is equal to zero, then that means our countdown is over and we should fade our countdown
number back off of the screen so we can use the fade element function again to get our countdown label.
And we want to make the duration like one second.
And we want to fade it out to be completely transparent.
And then after that we can set the countdown label that visibility back to false.
And that's all we need to do for our countdown function.
So now if we test this out again, our countdown should actually be working.
And perfect.
Now, as you can see, our countdown is up on top of the screen, showing us how much time we have left
to complete our tasks.
So what we can actually do is we can actually go ahead and test to see if our event, first of all,
is working.
So let's go ahead and complete our tasks first of all.
And studio, for some reason, is having this weird lagging problem.
As you can see that my mouse is moving around.
Just another weird bug unfortunately, I'm gonna have to deal with.
But we can get our tasks done here and see if our countdown fades out and all of our tasks get disabled.
So here we're completed our last task.
And when this gets finished here.
There we go.
Our timer has been disabled, but unfortunately, it looks like our for loop is still executing because
I think we forgot to break out of the for loop.
So let's go ahead and fix that real quick.
Right.
So after we have timed out or we have completed the tasks, we set the timer to zero.
And afterwards we actually need to go ahead and break out of this for loop because we do not need to
do the count anymore.
Okay.
Perfect.
Fix that.
Otherwise it seems to be working well and we can go ahead and continue what we need to do next in our
story.
The next thing I want to do is that after either the timeout occurs or the players complete their tasks,
is we want to start flickering the lights in the building until we lose power.
And we're also going to have Squidward talk in comment about the flickering lights.
So that means we can add some new text for Squidward here in our messages table, so we can create a
section called Squidward two, and we'll have some messages in here.
Like we could say, oh, great.
The storm is messing with the power.
And then we could say something like, hopefully we don't lose power completely.
And then after he says these, we're going to continue flickering the lights for a little bit until
we actually disable the power completely in the building.
And afterwards we can have them say another set of texts so we can call this Squidward three and he
can give some comments like, uh, we'll just put a bunch of dots so he'll be like, what?
And then he'll say, wow.
And then he'll say something like, I'm going.
To check the breaker in the basement.
And after he says that, we're also going to be putting some glow sticks behind them, that the players
can go ahead and collect so we can give them a message like there's some glow sticks behind me if you
need them.
And then he's going to say, stay here and don't do anything stupid.
And that's all the messages we need him to say for now.
And now we're going to need another few functions.
We're of course going to need a function.
We can call it flicker lights.
We're going to need a function to actually turn off the power in the building so we can call it turn
off power.
And basically what we're going to do is we're going to call this function to start flickering the lights.
So inside of here, what we can do is we can first create a variable, and we're going to collect all
of the flickering sounds that we have in the sound service.
So we can call it flicker sounds.
It's in the sound service.
And that means we're actually going to have to grab the sound service inside of the game section.
So let's go get that real quick.
Sound service is equal to game get service sound service.
And then we can go back down and inside of the sound service in the ambience folder dot light flicker.
We're going to get all of those sounds in there.
And they're just some generic light flickering sounds.
So if we actually go and take a look at those, we just have two in here.
We could play this one.
Or we could play this one pretty basic.
And what we're going to do inside of here is we'll just have a while loop that executes forever.
And we can have some boolean to keep track of whether or not we can continue flickering the lights until
we turn off the power.
So let's go ahead and create a boolean up here.
We'll just call it something like can Flicker Lights and we'll set that to false as default.
And then when we go down here we want to set can flicker lights equal to true.
And then we're going to use can flicker lights as the condition for this while loop.
So while can flicker lights is true.
What we could do is we could use our game comms event and fire to all of the clients in our game to
play a sound so we could do game comms enum on the client about two clients play sound.
The sound is going to be a random one out of our Flickr sounds folder, so it's going to be equal to
Flickr sounds, and we're just going to use our RNG data type next integer one to the length of our
Flickr sounds table.
And then we're just going to set play at point equal to false.
And then we're just going to wait a random amount of time.
We can do RNG next number way anywhere between 0.5 and 1.5 seconds.
And that means we're going to have to create another function to actually loop through all of the light
instances in the workspace and turn them off.
So we can create a function up here.
We can call it something like change lights, and we'll pass a boolean to it, to whether or not we
want to set the lights on or off so it can be set on.
This will be a boolean, and what we can do inside of this function is we're going to loop through every
single descendant inside of a folder in the workspace.
So in workspace dot krustikrab there's a folder called lights which stores all of the light instances.
So get descendants.
Where we're going to do is we're going to check if this descendant is of the type light.
So if it's a light instance then we need to set the descendant dot enable property equal to the boolean
passed to this function.
And then another thing we need to check is if this descendant is a base part, and we want to check
if this has the material.
So descendant dot material equal to the enum dot material dot neon.
Because if it's a neon part, then we want to either set the color to be black, or we want to set the
color back to its original state if we're turning on or off the lights.
So if the set on variable is false.
So if we need to turn it off, then we can set an attribute on this descendant.
Of original color.
That way we can keep track of what its color originally was, and we'll just pass descendant.
Color here.
And then we're going to set on this descendant dot color equal to a color three dot from RGB.
And it's just going to be black which is 000.
Otherwise, if we want to turn it on, then we can set on this descendant dot color equal to its attributes.
So descendant get attribute.
Our original color.
And that's all we need to do for our change lights function.
So inside of our while loop, while we're continually looping here, we need to basically.
Car, change lights function and pass a boolean to it.
Now the question you might have is how do we alternate the boolean to be true false true false each
time through this while loop?
Well, what we can do is we can create a boolean outside of here.
We're going to set it to false for now.
And we're going to pass this bool to our change lights function.
So through the first iteration of the loop we're going to turn all of the lights off.
And then afterwards what we can do is we can check if our bool is true.
If our bool is true then we can set bool equal to false.
Otherwise we can set bool equal to true.
So this will allow us to alternate our boolean each time through the iteration of our while loop.
And then finally, when we have decided that we flickered the lights enough, we can go ahead and turn
off the power in the building.
So what we would do is we would set can flicker lights equal to false.
And in order to actually, you know, turn off the power, we want to make sure that the lights are
on first off so we can use the change lights function and pass true here.
And we'll also make sure to apply another flicker sound.
So I'll just copy this right here.
And we're also going to have to grab the Flickr sounds as well, so we'll just do that real quick.
So we'll set can flicker lights to false, which will stop this while loop.
We set the lights to true and then after we set the lights to be back on, we're going to wait something
like 0.6 seconds, something like that.
And then we want to change the lights to be back off again.
And then we're going to use our exact same function again to play a sound.
But this time the sound we want to play is going to be inside of the sound service.
Dot ambience.
Dot.
I believe it's outage.
Yeah.
This sound instance.
Let me find it right here.
So when the power goes out we're going to play this sound.
Pretty spooky.
And after we do that inside of server storage, there's a folder called Other Stuff, and there's a
model in there called a glow stick giver.
And we want to set the parent equal to the workspace.
Let me go ahead and take a look at this real quick.
Inside of server storage.
Other stuff.
We have our glow stick giver.
When we put it in the workspace, it's going to appear directly behind Squidward.
And this is going to be a clickable part that the players can click to get glow sticks.
So we're going to have to fill out the function in here to give our players glow sticks, which is going
to be really easy.
The only service we're going to need inside of here is server storage game get service, server storage.
And then we're going to refer to the click detector in our model.
So click detector is equal to the script dot parent.
And then just get the click detector which is in the click part.
And then we're also going to get the glow stick tool we want to give to our players, which is in server
storage, dot tools, dot glow stick.
And then all we're going to do is we're going to listen for when our click detector is clicked.
So mouse click we're going to connect a function and get the player.
And we're going to check whether or not the player already has a glow stick.
So we're going to make a variable called tool.
And we're going to check inside the player dot backpack to see if we can find, uh, first child glow
stick.
Or if it's already on their character.
So or player character find first child glow stick.
If they already have the tool, then we're just going to return.
Otherwise, we can create a clone of our tool.
So glow stick tool clone.
And then we can set the clone dot parent equal to the player's backpack.
And that's all we need to do for this.
So now what we could do is we could go back to our start section one function.
And we can go ahead and call our flicker lights function.
Now remember there's a while loop in there.
So we don't want to get um, the thread of execution stuck in that while loop.
So we can use task dot spawn and spawn our flicker lights function in a new thread.
And then after that we can wait like two seconds.
And then we're going to use our message UI event and fire to all the players to send out a new message.
So actually we can just copy what we did right here.
And paste that here because it's going to be Squidward speaking same image.
And instead the message table for this one is going to be, uh, messages dot Squidward two and if the
cam was manipulated for message, we're going to set that equal to false because it wasn't.
And that means we're also going to have to calculate how long it'll take for these messages to display
on the screen.
So wait duration is going to be equal.
To calculate wait duration for text, we're going to pass messages dot Squidward two.
The time in between the messages is going to be again three seconds and then 0.02 for time in between
the characters.
And then we're going to wait for this wait duration.
And we're also going to add a little bit of extra time, like an extra, let's say six seconds.
And after that time is up, we're going to go ahead and turn off the power inside of the building,
and then we can use the game comms event and fire to all of the clients to start playing a new sound,
which is going to be the ambience for when the lights are off.
So again, inside of the sound service, inside of ambience we have eerie ambience one and this is going
to loop in play while the lights are off.
Yeah, sounds pretty spooky.
So we're going to use the action Game Comms enum for the client.
We want them to play a sound.
And that sound is going to be in the sound service ambience.
Eerie ambience one and play at point is going to be false.
And then to do a funny reference in our game inside of the server storage and our other stuff folder,
we actually have the hash slinging slasher in there, and we're going to set his parent to the workspace
as well.
So when the lights turn off, all you're going to see is him standing outside.
You'll just see a couple set of red glowing eyes.
I thought that'd be, you know, kind of funny to make them think that's who they're up against.
But that's not actually who they're up against.
So we set him to be inside of the workspace.
So let me actually go find him real quick.
Inside of server storage.
Where is he?
Here he is.
If we set his parent to the workspace, here he is.
He's just going to be standing out there.
This is just some free model that I found.
I thought it would be kind of funny, but when they're inside of the restaurant, they'll just see a
pair of red glowing eyes out there.
It'd be kind of neat.
Anyway, we can move them back inside of his folder, and if we set them to the workspace, we're again
going to wait for like, another two seconds here.
And then we're going to use our message UI event one more time.
And this time we want to send out the messages inside of the message three table or Squidward three
and again we can calculate the wait duration.
So wait duration is equal to.
Let me actually just copy this here.
And what we need to pass is Squidward three.
And then we're going to go ahead and wait for this wait duration.
And this is where we would go ahead and start moving, Squidward.
But we're going to do that in the next lecture to wrap up the introduction section or the first section
of our story, but we should go ahead and test out what we've gotten done so far.
And actually, before we start testing our game, make sure you move your glow stick giver back into
the other stuff folder.
There we go.
And now we can go ahead and test out our game.
Okay, that I filled up my last task here.
So once we finish this, the lights and the building should start to flicker.
And there we go.
The lights are flickering and Squidward is now talking to us.
Oh, great.
The storm is messing with the power.
Hopefully we don't lose power completely, and eventually the entire lights in our building should shut
off.
And there we go.
Our friend is all the way out there, standing creepily, and Squidward is talking to us.
And we also got our glow sticks here.
So if we click this boom, we get our nice glow stick to kind of allow us to see around the map.
And this gives players, you know, a little bit of time and opportunity to walk around the map and
collect some money.
So that's going to be very nice.
So other than that, our introduction or section one for the story is almost complete.
We just need to finish up a few more things, such as moving Squidward into the basement.
And other than that, we should be good to go for this lecture.
I'll go ahead and see you in the next one.